package com.mini.framework.ioc.reader;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.logging.Logger;

import com.mini.framework.ioc.BeanReader;
import com.mini.framework.ioc.annotation.Component;
import com.mini.framework.ioc.annotation.Controller;

public class AnnotationReader implements BeanReader {
	
	private Logger log = Logger.getLogger("AnnotationReader");
	
	private Properties properties;
	
	private static AnnotationReader instance ;
	
	private static final String ComponentPath = "componentPath";
	
	private static final String SplitChar = ",";
	
	private Set<Class<?>> clazz;
	

	@Override
	public Set<Class<?>> getClasses() {
		return clazz;
	}
	
	public Properties getProperties() {
		return properties;
	}
	
	public static AnnotationReader getInstance(){
		if(instance == null)
			instance = new AnnotationReader();
		
		return instance;
	}
	
	private AnnotationReader(){
		clazz = new LinkedHashSet<Class<?>>();
		properties = new Properties();
		try{
			properties.load(AnnotationReader.class.getResourceAsStream(DefaultConfFile));
		}catch(Exception e){
			e.printStackTrace();
		}
		String[] componentPaths = properties.getProperty(ComponentPath).split(SplitChar);
		for(String pack:componentPaths){
			scan(pack.trim());
		}
	}
	
	private void scan(String pack){
		String packageName = pack;
		String packageDirName = packageName.replace('.', '/');
		Enumeration<URL> dirs = null;

		try {
			dirs = Thread.currentThread().getContextClassLoader().getResources(
					packageDirName);
		} catch (IOException e) {
			e.printStackTrace();
		}
		while (dirs.hasMoreElements()) {
			URL url = dirs.nextElement();
			String protocol = url.getProtocol();
			if ("file".equals(protocol)) {
				String filePath = null;
				try {
					filePath = URLDecoder.decode(url.getFile(), "UTF-8");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				try {
					addClassesByFile(packageName, filePath);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			} else if ("jar".equals(protocol)) {
				try {
					JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile();

					//addClassesByJar(packageName, packageDirName, jar);
				} catch (IOException e) {
					e.printStackTrace();
				} 
			}
		}
	}
	
	private void addClassesByFile(String packageName, String filePath) throws ClassNotFoundException {
		File dir = new File(filePath);
		if (!dir.exists() || !dir.isDirectory()) {
			return;
		}
		File[] dirfiles = dir.listFiles(new FileFilter() {
			public boolean accept(File file) {
				return file.isDirectory() || file.getName().endsWith(".class");
			}
		});
		for (File file : dirfiles) {
			if (file.isDirectory()) {
				addClassesByFile(packageName + "." + file.getName(), file.getAbsolutePath());
			} else {
				
				
				String className = file.getName().substring(0,file.getName().length() - 6);
				Class<?> c = Thread.currentThread().getContextClassLoader()
						.loadClass(packageName + '.' + className);

				if (isAnnotationPresent(c)) {
					clazz.add(c);
				}

			}
		}
	}
	
	private boolean isAnnotationPresent(Class<?> c) {
		return  c.isAnnotationPresent(Component.class)||c.isAnnotationPresent(Controller.class);
	}
	
	

}
